#pragma once

#include<iostream>
#include<string>
#include<memory>
#include<cerrno>
#include<functional>
#include<unordered_map>
#include"Log.hpp"
#include"nocopy.hpp"
#include"Epoller.hpp"
#include"Socket.hpp"
#include"Comm.hpp"

class Connection;
class TcpServer;

uint32_t EVENT_IN = (EPOLLIN |EPOLLET);//(文件描述符读写变化)边沿触发:EPOLLET
uint32_t EVENT_OUT = (EPOLLOUT|EPOLLET);

const static int g_buffer_size = 128;

using func_t = std::function<void(std::weak_ptr<Connection>)>;
using except_func = std::function<void(std::weak_ptr<Connection>)>;

class Connection{
public:
    Connection(int sock):_sock(sock){
    }
    
    void SetHandler(func_t recv_cb, func_t send_cb, except_func except_cb){
        _recv_cb = recv_cb;
        _send_cb = send_cb;
        _except_cb = except_cb;
    }

    int SockFd(){ return _sock; }
    
    void AppendInbuffer(const std::string &info){
        _inbuffer += info;
    }

    void AppendOutBuffer(const std::string &info){
        _outbuffer += info;
    }

    std::string &Inbuffer(){
        return _inbuffer;
    }
    
    std::string &OutBuffer(){
        return _outbuffer;
    }

    void SetWeakPtr(std::weak_ptr<TcpServer> tcp_server_ptr){
        _tcp_server_ptr=tcp_server_ptr;
    }

    ~Connection(){}
private:
    int _sock;
    std::string _inbuffer;
    std::string _outbuffer;
public:
    func_t _recv_cb;
    func_t _send_cb;
    except_func _except_cb;

    //回指指针
    std::weak_ptr<TcpServer> _tcp_server_ptr;
    
    std::string _ip;//对方主机的端口和ip地址
    uint16_t _port;
};


class TcpServer: public std::enable_shared_from_this<TcpServer>,public nocopy
{
    static const int num = 64;
public:
    TcpServer(uint16_t port,func_t OnMessage)
    :_port(port),
    _OnMessage(OnMessage),
    _quit(true),
    _epoller_ptr(new Epoller()),
    _listensock_ptr(new Sock()){
    }
    void Init(){
        _listensock_ptr ->Socket();//创建套接字
        SetNonBlockOrDie(_listensock_ptr->Fd());//设置非阻塞
        _listensock_ptr->Bind(_port);
        _listensock_ptr->Listen();
        lg(Info,"create listen socket success: %d",_listensock_ptr->Fd());
        AddConnection(_listensock_ptr->Fd(),
            EVENT_IN,std::bind(&TcpServer::Accepter, this, std::placeholders::_1),nullptr,nullptr);
    }
    
    void AddConnection(int sock, uint32_t event, func_t recv_cb,func_t send_cb,
        except_func except_cb, const std::string &ip="0.0.0.0",uint16_t port = 0)
    {
        //1.创建链接
        std::shared_ptr<Connection> new_connection(new Connection(sock));
        new_connection->SetWeakPtr(shared_from_this());  //返回自身的sheared_ptr<TcpServer>
        new_connection->SetHandler(recv_cb, send_cb, except_cb);
        new_connection->_ip = ip;
        new_connection->_port = port;
        // 2.添加到unordered_map
        _connections.insert(std::make_pair(sock,new_connection));
        //3.我们添加对应的事件，除了要加到内核中
        _epoller_ptr->EpollerUpdate(EPOLL_CTL_ADD,sock,event);
    }
    //链接管理器
    void Accepter(std::weak_ptr<Connection> conn){
        auto connection = conn.lock();
        while(true){
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);
            int sock = ::accept(connection->SockFd(),(struct sockaddr *)&peer, &len);
            if(sock>0){
                uint16_t peerport = ntohs(peer.sin_port);
                char ipbuf[128];
                inet_ntop(AF_INET,&peer.sin_addr.s_addr,ipbuf,sizeof(ipbuf));
                lg(Debug,"get a new client, get info-> [%s:%d],sockfd: %d",ipbuf,peerport,sock);
                
                SetNonBlockOrDie(sock);
                AddConnection(sock, EVENT_IN,
                    std::bind(&TcpServer::Recver,this,std::placeholders::_1),
                    std::bind(&TcpServer::Sender,this,std::placeholders::_1),
                    std::bind(&TcpServer::Excepter,this,std::placeholders::_1),
                    ipbuf, peerport);
            }else{
                if(errno == EWOULDBLOCK){
                    break;
                }else if(errno == EINTR){
                    continue;
                }
                else
                    break;
            }
        }
    }

    //事件管理器
    void Recver(std::weak_ptr<Connection> conn){
        if(conn.expired()) return ;
        auto connection =conn.lock();//.lock()返回shared_ptr
        
        int sock = connection->SockFd();
        while (true)
        {
            char buffer[g_buffer_size];
            memset(buffer,0,sizeof(buffer)-1);//非阻塞读取
            ssize_t n=recv(sock,buffer,sizeof(buffer)-1,0);
            if(n>0){
                connection->AppendInbuffer(buffer);
            }else if(n==0){
                lg(Info,"sockfd: %d,client info %s:%d quit...",sock,connection->_ip.c_str(),connection->_port);
                connection->_except_cb(connection);
                return;
            }else{
                if(errno == EWOULDBLOCK) break;//阻塞队列已满
                else if(errno == EINTR) continue;//系统调用被信号中断
                else{
                    lg(Warning,"sockfd: %d,client info %s:%d,recv error...",sock,connection->_ip.c_str(),connection->_port);
                    connection->_except_cb(connection);
                    return;
                }
            }
        }
        _OnMessage(connection);
    }

    void Sender(std::weak_ptr<Connection> conn){
        if(conn.expired()) return;
        auto connection = conn.lock();
        auto &outbuffer = connection->OutBuffer();
        while (true)
        {
            ssize_t n = send(connection->SockFd(),outbuffer.c_str(),outbuffer.size(),0);
            if(n > 0){
                outbuffer.erase(0,n);
                if(outbuffer.empty()) break;
            }else if(n==0){
                return;
            }else{
                if(errno == EWOULDBLOCK) break;
                else if(errno == EINTR) continue;
                else{
                    lg(Warning,"sockfd: %d, client info %s:%d send error...",connection->SockFd(),
                        connection->_ip.c_str(),connection->_port);
                    connection->_except_cb(connection);
                    return;
                }
            }
        }
        if(!outbuffer.empty()){
            EnableEvent(connection->SockFd(),true,true);
        }else{
            EnableEvent(connection->SockFd(),true,false);
        }
    }

    void Excepter(std::weak_ptr<Connection> connection){
        if(connection.expired()) return;
        auto conn = connection.lock();
        
        int fd = conn->SockFd();
        lg(Warning, "Excepter hander sockfd: %d, client info %s:%d excepter handler",
            conn->SockFd(), conn->_ip.c_str(),conn->_port);
        
        _epoller_ptr -> EpollerUpdate(EPOLL_CTL_DEL,fd,0);
        lg(Debug, "close %d done...\n", fd);
        close(fd);
        lg(Debug,"remove %d from_connection...\n",fd);
        
        _connections.erase(fd);
    }
    


    void EnableEvent(int sock, bool readable,bool writeable){
        uint32_t events = 0;
        events |= ((readable?EPOLLIN : 0) | (writeable ? EPOLLOUT : 0) | EPOLLET);
        _epoller_ptr -> EpollerUpdate(EPOLL_CTL_MOD, sock, events);
    }

    bool IsConnectionSafe(int fd){
        auto iter = _connections.find(fd);
        if(iter == _connections.end()){
            return false;
        }else
            return true;
    }

    void Dispatcher(int timeout){
        int n = _epoller_ptr->EpollerWait(revs,num,timeout);
        std::cout<<"n1: "<<n<<std::endl;
        for(int i=0;i<n;i++){
            std::cout<<"n2: "<<n<<std::endl;
            uint32_t events = revs[i].events;
            int sock = revs[i].data.fd;
            std::cout<<"sock3:"<<sock<<std::endl;
            if(!IsConnectionSafe(sock)) std::cout<<"sock4:"<<sock<<std::endl;
            if((events&EPOLLIN) && IsConnectionSafe(sock)){
                std::cout<<"sock5:"<<sock<<std::endl; //sock5:4, 文件4响应
                if(_connections[sock]->_recv_cb){  
                    std::cout<<"sock6:"<<sock<<std::endl; //_recv_cb:应该是Accept
                    _connections[sock]->_recv_cb(_connections[sock]);//文件4接受
                }
            }else if((events & EPOLLOUT)&&IsConnectionSafe(sock)){
                if(_connections[sock]->_send_cb){
                    _connections[sock]->_send_cb(_connections[sock]);
                }
            }else{

            }
        }
    }

    void Loop(){
        _quit = false;
        while(!_quit){
            Dispatcher(3000);
            // Dispatcher(-1);
            PrintConnection();
        }
        _quit = true;
    }

    void PrintConnection(){
        std::cout<<"_connection fd list: ";
        for(auto &connection: _connections){
            std::cout<<connection.second->SockFd()<<", ";
            std::cout<<"inbuffer: "<<connection.second->Inbuffer().c_str();
        }
        std::cout<<std::endl;
    }
    ~TcpServer(){

    }

private:
    std::shared_ptr<Epoller> _epoller_ptr;
    std::shared_ptr<Sock>_listensock_ptr;
    std::unordered_map<int, std::shared_ptr<Connection>> _connections;
    struct epoll_event revs[num];
    uint16_t _port;
    bool _quit;
    //上层处理信息
    func_t _OnMessage;   
};
